#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>  // 添加此头文件来支持wait函数
#include <fcntl.h>
#include <string.h>

#define ITERATIONS 100000  // 设置测试的迭代次数

// 计算时间差，单位微秒
long calculate_time_diff(struct timeval start, struct timeval end) {
    return (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
}

int main() {
    int pipefd[2];  // 用于父子进程间通信的管道
    pid_t pid;
    struct timeval start_time, end_time;
    long total_time = 0;

    // 创建管道
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(1);
    }

    // 创建子进程
    pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(1);
    }

    if (pid > 0) {
        // 父进程
        close(pipefd[0]);  // 关闭读取端

        // 记录开始时间并打印调试信息
        gettimeofday(&start_time, NULL);
        printf("Start time: %ld.%06ld\n", start_time.tv_sec, start_time.tv_usec);
        fflush(stdout);  // 确保输出被立即打印

        for (int i = 0; i < ITERATIONS; i++) {
            write(pipefd[1], "ping", 4);  // 父进程向管道写入数据
            read(pipefd[0], NULL, 0);    // 父进程从管道读取数据，触发切换
        }

        // 等待子进程结束
        wait(NULL);

        // 记录结束时间并打印调试信息
        gettimeofday(&end_time, NULL);
        printf("End time: %ld.%06ld\n", end_time.tv_sec, end_time.tv_usec);
        fflush(stdout);  // 确保输出被立即打印

        // 计算总时间并输出每次进程切换的时间
        total_time = calculate_time_diff(start_time, end_time);
        printf("Total time: %ld microseconds\n", total_time);
        printf("Average time per context switch: %ld microseconds\n", total_time / ITERATIONS);

    } else {
        // 子进程
        close(pipefd[1]);  // 关闭写入端

        for (int i = 0; i < ITERATIONS; i++) {
            read(pipefd[0], NULL, 0);  // 子进程从管道读取数据
            write(pipefd[1], "pong", 4);  // 子进程向管道写入数据
        }

        // 子进程完成后打印一条信息，确保子进程确实运行了
        printf("Child process finished\n");
        fflush(stdout);  // 确保子进程输出被立即打印
        exit(0);  // 确保子进程退出时正确结束
    }

    // 关闭管道
    close(pipefd[0]);
    close(pipefd[1]);

    return 0;
}

